package com.cow.framework.core.schedule;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

import org.hibernate.service.spi.ServiceException;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.cow.framework.utils.date.DateUtil;

@Service  
public class TaskService{  
    @Autowired  
    private Scheduler scheduler;  
  
    /** 
     * 所有任务列表 
     */  
    public List<TaskInfo> list(){  
        List<TaskInfo> list = new ArrayList<>();  
  
        try {  
            for(String groupJob: scheduler.getJobGroupNames()){  
                for(JobKey jobKey: scheduler.getJobKeys(GroupMatcher.<JobKey>groupEquals(groupJob))){  
                    List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);  
                    for (Trigger trigger: triggers) {  
                        Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());  
                        JobDetail jobDetail = scheduler.getJobDetail(jobKey);  
  
                        String cronExpression = "", createTime = "";  
  
                        if (trigger instanceof CronTrigger) {  
                            CronTrigger cronTrigger = (CronTrigger) trigger;  
                            cronExpression = cronTrigger.getCronExpression();  
                            createTime = cronTrigger.getDescription();  
                        }  
                        TaskInfo info = new TaskInfo();  
                        info.setJobName(jobKey.getName());  
                        info.setJobGroup(jobKey.getGroup());  
                        info.setJobDescription(jobDetail.getDescription());  
                        info.setJobStatus(triggerState.name());  
                        info.setCronExpression(cronExpression);  
                        info.setCreateTime(createTime);  
                        list.add(info);  
                    }                     
                }  
            }             
        } catch (SchedulerException e) {  
            e.printStackTrace();  
        }  
  
        return list;  
    }  
  
    /** 
     * 保存定时任务 
     */  
    public void addJob(TaskInfo info) {  
        String jobName = info.getJobName(),   
               jobGroup = info.getJobGroup(),   
               cronExpression = info.getCronExpression(),  
               jobDescription = info.getJobDescription(),  
               createTime = DateUtil.sysdate();  
        try {  
            if (checkExists(jobName, jobGroup)) {  
                throw new ServiceException(String.format("任务已存在，不必重新设置, jobName:{%s},jobGroup:{%s}", jobName, jobGroup));  
            }  
  
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);  
            JobKey jobKey = JobKey.jobKey(jobName, jobGroup);  
  
            CronScheduleBuilder schedBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();  
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withDescription(createTime).withSchedule(schedBuilder).build();  
  
            Class<? extends Job> clazz = (Class<? extends Job>)Class.forName(jobName);  
            JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(jobKey).withDescription(jobDescription).build(); 
            jobDetail.getJobDataMap().putAll(info.getJobDataMap());
            scheduler.scheduleJob(jobDetail, trigger);  
        } catch (SchedulerException | ClassNotFoundException e) {  
        	e.printStackTrace();
            throw new ServiceException("类名不存在或执行表达式错误");  
        }  
    }  
  
    /** 
     * 修改定时任务 
     */  
    public void edit(TaskInfo info) {  
        String jobName = info.getJobName(),   
               jobGroup = info.getJobGroup(),   
               cronExpression = info.getCronExpression(),  
               jobDescription = info.getJobDescription(),  
               createTime = DateUtil.sysdate();  
        try {  
            if (!checkExists(jobName, jobGroup)) {  
                throw new ServiceException(String.format("Job不存在, jobName:{%s},jobGroup:{%s}", jobName, jobGroup));  
            }  
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);  
            JobKey jobKey = new JobKey(jobName, jobGroup);  
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();  
            CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withDescription(createTime).withSchedule(cronScheduleBuilder).build();  
  
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);  
            jobDetail.getJobBuilder().withDescription(jobDescription);  
            HashSet<Trigger> triggerSet = new HashSet<>();  
            triggerSet.add(cronTrigger);  
  
            scheduler.scheduleJob(jobDetail, triggerSet, true);  
        } catch (SchedulerException e) {  
            throw new ServiceException("类名不存在或执行表达式错误");  
        }  
    }  
  
    /** 
     * 删除定时任务 
     */  
    public void delete(String jobName, String jobGroup){  
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);  
        try {  
            if (checkExists(jobName, jobGroup)) {  
                scheduler.pauseTrigger(triggerKey);  
                scheduler.unscheduleJob(triggerKey);  
            }  
        } catch (SchedulerException e) {  
            throw new ServiceException(e.getMessage());  
        }  
    }  
  
    /** 
     * 验证是否存在 
     */  
    private boolean checkExists(String jobName, String jobGroup) throws SchedulerException{  
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);  
        return scheduler.checkExists(triggerKey);  
    }  
}  